{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "72db2c74-0ead-4a13-a524-273e61999ff1",
   "metadata": {},
   "source": [
    "## 默认查询参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ed36c19-045b-4030-96ea-49b7c1454ca3",
   "metadata": {},
   "source": [
    "声明不属于路径参数的其他函数参数时，它们将被自动解释为\"查询字符串\"参数\n",
    "\n",
    "查询字符串是键值对的集合，这些键值对位于 URL 的 ？ 之后，并以 & 符号分隔。\n",
    "\n",
    "例如，在以下 url 中：\n",
    "\n",
    "http://127.0.0.1:8000/items/?skip=0&limit=10\n",
    "\n",
    "查询参数为：\r\n",
    "\r\n",
    "skip：对应的值为   0\r\n",
    "limit：对应的值为   10\r\n",
    "由于它们是 URL 的一部分，因此它们的\"原始值\"是字符串。\r\n",
    "\r\n",
    "但是，当你为它们声明了 Python 类型（在上面的示例中为 int）时，它们将转换为该类型并针对该类型进行校验。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ba66f862-fd0c-48d9-a263-b84aeee0582e",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Started server process [20824]\n",
      "INFO:     Waiting for application startup.\n",
      "INFO:     Application startup complete.\n",
      "INFO:     Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     127.0.0.1:54845 - \"GET /items/ HTTP/1.1\" 200 OK\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Shutting down\n",
      "INFO:     Waiting for application shutdown.\n",
      "INFO:     Application shutdown complete.\n",
      "INFO:     Finished server process [20824]\n"
     ]
    }
   ],
   "source": [
    "import uvicorn\n",
    "from fastapi import FastAPI\n",
    "\n",
    "app = FastAPI()\n",
    "\n",
    "fake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n",
    "\n",
    "\n",
    "@app.get(\"/items/\")\n",
    "async def read_item(skip: int = 0, limit: int = 10):\n",
    "    return fake_items_db[skip : skip + limit]\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "raw",
   "id": "a55414f0-fce1-4516-b457-0053bd290521",
   "metadata": {},
   "source": [
    "由于查询参数不是路径的固定部分，因此它们可以是可选的，并且可以有默认值。\n",
    "\n",
    "在上面的示例中，它们具有 skip=0 和 limit=10 的默认值。\n",
    "\n",
    "因此，访问 URL：\r\n",
    "http://127.0.0.1:80//0items/\r\n",
    "将与访问以址相同http://127.0.0.1:8000/items/?skip=0&limit=10i\n",
    "\n",
    "但是，如果你访问的是：\n",
    "\n",
    "http://127.0.0.1:8000/items/?skip=20\n",
    "函数中的参数值将会是：\n",
    "\n",
    "skip=20：在 URL 中设定的值\n",
    "limit=10：使用默认值：使用默认值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6688f832-270f-43dc-8450-5f367ddd8768",
   "metadata": {},
   "source": [
    "## 必需查询参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "678bab30-6c48-4d33-b656-66d4a194a2cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "当你为非路径参数声明了默认值时（目前而言，我们所知道的仅有查询参数），则该参数不是必需的。\n",
    "\n",
    "如果你不想添加一个特定的值，而只是想使该参数成为可选的，则将默认值设置为 None。\n",
    "\n",
    "但当你想让一个查询参数成为必需的，不声明任何默认值就可以："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c7bcc003-fa43-483c-b4dc-cb024be44b53",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Started server process [20824]\n",
      "INFO:     Waiting for application startup.\n",
      "INFO:     Application startup complete.\n",
      "INFO:     Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     127.0.0.1:55313 - \"GET /items/4?needy=yes HTTP/1.1\" 200 OK\n",
      "INFO:     127.0.0.1:55358 - \"GET /items/4 HTTP/1.1\" 422 Unprocessable Entity\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Shutting down\n",
      "INFO:     Waiting for application shutdown.\n",
      "INFO:     Application shutdown complete.\n",
      "INFO:     Finished server process [20824]\n"
     ]
    }
   ],
   "source": [
    "import uvicorn\n",
    "from fastapi import FastAPI\n",
    "\n",
    "app = FastAPI()\n",
    "\n",
    "\n",
    "@app.get(\"/items/{item_id}\")\n",
    "async def read_user_item(item_id: str, needy: str):\n",
    "    item = {\"item_id\": item_id, \"needy\": needy}\n",
    "    return item\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f80faf9e-bd10-4ca3-9a14-c75d329ecac4",
   "metadata": {},
   "source": [
    "这里的查询参数 needy 是类型为 str 的必需查询参数。\n",
    "\n",
    "浏览器输入 http://127.0.0.1:8009/items/4?needy=yes\r\n",
    "\r\n",
    "会看{\"item_id\":\"4\",\"needy\":\"yes\"}\n",
    "\n",
    "如果浏览器输入 http://127.0.0.1:8009/items/4\n",
    "\n",
    "会报错 {\"detail\":[{\"type\":\"missing\",\"loc\":[\"query\",\"needy\"],\"msg\":\"Field required\",\"input\":null,\"url\":\"https://errors.pydantic.dev/2.5/v/missing\"}]}\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1cf5fd2d-9415-40c8-a25b-ebdd4779f880",
   "metadata": {},
   "source": [
    "## 可选查询参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b996646-40a2-45ab-9f2a-76eaef789229",
   "metadata": {},
   "source": [
    "通过同样的方式，你可以将它们的默认值设置为 None 来声明可选查询参数：\n",
    "在这个例子中，函数参数 q 将是可选的，并且默认值为 None。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4c99409c-da82-4308-8531-5d3148c1200c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Started server process [20824]\n",
      "INFO:     Waiting for application startup.\n",
      "INFO:     Application startup complete.\n",
      "INFO:     Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     127.0.0.1:55114 - \"GET /items/4 HTTP/1.1\" 200 OK\n",
      "INFO:     127.0.0.1:55137 - \"GET /items/4?q=hello HTTP/1.1\" 200 OK\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Shutting down\n",
      "INFO:     Waiting for application shutdown.\n",
      "INFO:     Application shutdown complete.\n",
      "INFO:     Finished server process [20824]\n"
     ]
    }
   ],
   "source": [
    "import uvicorn\n",
    "from typing import Union\n",
    "from fastapi import FastAPI\n",
    "\n",
    "app = FastAPI()\n",
    "\n",
    "@app.get(\"/items/{item_id}\")\n",
    "async def read_item(item_id: str, q: Union[str, None] = None):\n",
    "    if q:\n",
    "        return {\"item_id\": item_id, \"q\": q}\n",
    "    return {\"item_id\": item_id}\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1aa6a68f-0c85-4fba-b1b9-4cc3dbca5133",
   "metadata": {},
   "source": [
    "浏览器输入 http://127.0.0.1:8009/items/4\n",
    "\n",
    "会看到 {\"item_id\":\"4\"}\n",
    "\n",
    "输入 http://127.0.0.1:8009/items/4?q=hello\n",
    "\n",
    "会看到 {\"item_id\":\"4\",\"q\":\"hello\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f9de21f-5cb9-4822-80ed-ce94db870fc6",
   "metadata": {},
   "source": [
    "当然，你也可以定义一些参数为必需的，一些具有默认值，而某些则完全是可选的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2dbec773-a0c5-44f2-8e47-d60e92c282b9",
   "metadata": {},
   "outputs": [],
   "source": [
    "import uvicorn\n",
    "from typing import Union\n",
    "from fastapi import FastAPI\n",
    "app = FastAPI()\n",
    "@app.get(\"/items/{item_id}\")\n",
    "async def read_user_item(\n",
    "    item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None\n",
    "):\n",
    "    item = {\"item_id\": item_id, \"needy\": needy, \"skip\": skip, \"limit\": limit}\n",
    "    return item\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "123fb276-322f-4f54-a5a0-d9bcf5ccd7fa",
   "metadata": {},
   "source": [
    "在这个例子中，有3个查询参数：\n",
    "\n",
    "needy，一个必需的 str 类型参数。\n",
    "\r\n",
    "skip，一个默认值为 0 的 int 类参数。\n",
    "。\r\n",
    "limit，一个可选的 in类型参数。 数\n",
    "\n",
    "你还可以像在 路径参数 中那样使用numn。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02a44fb1-4b39-4198-86c0-8c5bbde3847c",
   "metadata": {},
   "source": [
    "## 多个路径和查询参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0fc04547-4cac-4053-ab19-06d4b7142885",
   "metadata": {},
   "source": [
    "你可以同时声明多个路径参数和查询参数，FastAPI 能够识别它们。\n",
    "\n",
    "而且你不需要以任何特定的顺序来声明。\n",
    "\n",
    "它们将通过名称被检测到："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7d64f136-cf85-4bb5-969b-156234914e3c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Started server process [20824]\n",
      "INFO:     Waiting for application startup.\n",
      "INFO:     Application startup complete.\n",
      "INFO:     Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     127.0.0.1:55415 - \"GET /users/3/items/4?q=foo&short=yes HTTP/1.1\" 200 OK\n",
      "INFO:     127.0.0.1:55433 - \"GET /users/3/items/4?q=foo HTTP/1.1\" 200 OK\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Shutting down\n",
      "INFO:     Waiting for application shutdown.\n",
      "INFO:     Application shutdown complete.\n",
      "INFO:     Finished server process [20824]\n"
     ]
    }
   ],
   "source": [
    "import uvicorn\n",
    "from typing import Union\n",
    "from fastapi import FastAPI\n",
    "app = FastAPI()\n",
    "@app.get(\"/users/{user_id}/items/{item_id}\")\n",
    "async def read_user_item(\n",
    "    user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False\n",
    "):\n",
    "    item = {\"item_id\": item_id, \"owner_id\": user_id}\n",
    "    if q:\n",
    "        item.update({\"q\": q})\n",
    "    if not short:\n",
    "        item.update(\n",
    "            {\"description\": \"This is an amazing item that has a long description\"}\n",
    "        )\n",
    "    return item\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f9c530c-95c6-4210-b62a-1a4276076941",
   "metadata": {},
   "source": [
    "浏览器输入 http://127.0.0.1:8009/users/3/items/4?q=foo&short=yes\n",
    "\n",
    "会看到 {\"item_id\":\"4\",\"owner_id\":3,\"q\":\"foo\"}\n",
    "\n",
    "浏览器输入 http://127.0.0.1:8009/users/3/items/4?q=foo\n",
    "\n",
    "会看到 {\"item_id\":\"4\",\"owner_id\":3,\"q\":\"foo\",\"description\":\"This is an amazing item that has a long description\"}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
